//
//  KDLockTest.m
//  demo
//
//  Created by 叶青 on 15/6/24.
//  Copyright (c) 2015年 naruto. All rights reserved.
//

#import "KDLockTest.h"
#import <libkern/OSAtomic.h>
#import <pthread.h>


#define ITERATIONS (1024*1024*32)


@interface KDLockTest()
@property (nonatomic, strong) NSString *lock;      //lock
@property (atomic, strong) NSMutableArray *listClothes;      //衣服
@end


@implementation KDLockTest
{
    OSSpinLock                  _oslock;
    NSLock                      *_oclock;
    NSRecursiveLock             *_recursivelock;
    pthread_mutex_t             _threadmutex;
//    NSDistributedLock           *_distributedlock;
    NSConditionLock             *_conditionlock;
    dispatch_semaphore_t        _semaphoreLock;
}
#pragma mark - system
-(instancetype)init
{
    self=[super init];
    if(self){
        _lock=@"testlock";
        _oslock=OS_SPINLOCK_INIT;
        _oclock=[NSLock new];
        _recursivelock=[NSRecursiveLock new];
        pthread_mutex_init(&_threadmutex, NULL);
        _conditionlock=[NSConditionLock new];
        _semaphoreLock=dispatch_semaphore_create(1);
        
        _listClothes=[NSMutableArray new];
        [_listClothes addObject:@"红衣服"];
        [_listClothes addObject:@"黄衣服"];
        [_listClothes addObject:@"蓝衣服"];
    }
    return self;
}
#pragma mark - 吃
/**
 *  吃饭
 *  @param count:次数
 *  @return void
 */
- (void)eat:(NSInteger )count
{
    NSLog(@"eat :%@",[[NSThread currentThread] description]);
//    //.synchronized
//    @synchronized(self){
//        NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//        [NSThread sleepForTimeInterval:5];
//        NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//    }
//    bool getlock= OSSpinLockTry(&_oslock);//获取锁，成功返回true，否则返回false
    
//    //.spinLock
//    OSSpinLockLock(&_oslock);
//    NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//    OSSpinLockUnlock(&_oslock);
    
    
//    //.nslock
//    [_oclock lock];
//    NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//    [_oclock unlock];
    
//    //.NSRecursiveLock
//    [_recursivelock lock];
//    NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//    if(count>0){
//        count--;
//        [self eat:count];
////        [NSThread sleepForTimeInterval:5];
////        NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//    }
//    NSLog(@"eat end:%@",[[NSThread currentThread] description]);
//    [_recursivelock unlock];
    
    
//    //.pthread_mutex
//    pthread_mutex_lock(&_threadmutex);
//    NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//    pthread_mutex_unlock(&_threadmutex);
   
    
//    //.conditionlock
//    for (int i=0;i<=2;i++)
//    {
//        [_conditionlock lock];
//        NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
//        sleep(5);
//        NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
//        [_conditionlock unlockWithCondition:i];
//    }
    
    
    //.dispatch_semaphore
    dispatch_semaphore_wait(_semaphoreLock, DISPATCH_TIME_FOREVER);
    NSLog(@"eat begin:%@",[[NSThread currentThread] description]);
    [NSThread sleepForTimeInterval:5];
    NSLog(@"eat complate:%@",[[NSThread currentThread] description]);
    dispatch_semaphore_signal(_semaphoreLock);
    
//    dispatch_semaphore_t dsemObj = dispatch_semaphore_create(1);
//    __block long varTest = 0;
//    NSLog(@"test begin:%ld",varTest);
//    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//        sleep(2);
//        NSLog(@"signal 1 ，2s过去了");
//        varTest = dispatch_semaphore_signal(dsemObj);
//        NSLog(@"signal 1 done:%ld",varTest);
//        
//        sleep(2);
//        NSLog(@"signal 2，2s过去了");
//        varTest = dispatch_semaphore_signal(dsemObj);
//        NSLog(@"signal 2 done:%ld",varTest);
//    });
//    
//    NSLog(@"wait 1");
//    varTest = dispatch_semaphore_wait(dsemObj, DISPATCH_TIME_FOREVER);
//    NSLog(@"wait 1 done:%ld",varTest);
//    
//    NSLog(@"wait 2");
//    varTest = dispatch_semaphore_wait(dsemObj, DISPATCH_TIME_FOREVER);
//    NSLog(@"wait 2 done:%ld",varTest);
//    
//    NSLog(@"wait 3");
//    varTest = dispatch_semaphore_wait(dsemObj, DISPATCH_TIME_FOREVER);
//    NSLog(@"wait 3 done:%ld",varTest);
//    
//    NSLog(@"test end:%ld",varTest);
}

#pragma mark - 喝水
/**
 *  喝水
 *  @param void
 *  @return void
 */
- (void)drink
{
     NSLog(@"drink :%@",[[NSThread currentThread] description]);
//    //.synchronized
//    @synchronized(self){
//        NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//        [NSThread sleepForTimeInterval:5];
//        NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    }
    
//    //.spinLock
//    OSSpinLockLock(&_oslock);
//    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    OSSpinLockUnlock(&_oslock);
    
    
//    //.nslock
//    [_oclock lock];
//    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    [_oclock unlock];

    
//    //.NSRecursiveLock
//    [_recursivelock lock];
//    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    [_recursivelock unlock];
    
//    //.pthread_mutex
//    pthread_mutex_lock(&_threadmutex);
//    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//    [NSThread sleepForTimeInterval:5];
//    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    pthread_mutex_unlock(&_threadmutex);
    
    
//    //.conditionlock
//    [_conditionlock lockWhenCondition:2];
//    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
//    sleep(5);
//    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
//    [_conditionlock unlock];
    
    
    //.dispatch_semaphore
    dispatch_semaphore_wait(_semaphoreLock, DISPATCH_TIME_FOREVER);
    NSLog(@"drink begin:%@",[[NSThread currentThread] description]);
    [NSThread sleepForTimeInterval:5];
    NSLog(@"drink complate:%@",[[NSThread currentThread] description]);
    dispatch_semaphore_signal(_semaphoreLock);
    
    NSLog(@"drink end:%@",[[NSThread currentThread] description]);
    
}

#pragma mark - 衣服
/**
 *  穿衣服
 *  @param void
 *  @return void
 */
- (void)dressClothe
{
    NSLog(@"dressClothe begin:%@",[[NSThread currentThread] description]);
    [self.listClothes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"dressClothe :%@",obj);
    }];
//    for (NSInteger i=0; i<self.listClothes.count; i++) {
//        NSLog(@"dressClothe :%@",self.listClothes[i]);
//    }
    NSLog(@"dressClothe complate:%@",[[NSThread currentThread] description]);
}

/**
 *  脱衣服
 *  @param void
 *  @return void
 */
- (void)undressClothe
{
    NSLog(@"undressClothe begin:%@",[[NSThread currentThread] description]);
    [self.listClothes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"undressClothe :%@",obj);
    }];
//    for (NSInteger i=0; i<self.listClothes.count; i++) {
//        NSLog(@"undressClothe :%@",self.listClothes[i]);
//    }
    NSLog(@"undressClothe complate:%@",[[NSThread currentThread] description]);
}


#pragma mark - 性能测试

#pragma mark - 测试各种锁性能
/**
 *  测试各种锁性能
 *  @param void
 *  @return void
 */
- (void)testLock
{
    double then, now;
    unsigned int i;
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    OSSpinLock spinlock = OS_SPINLOCK_INIT;
    
    @autoreleasepool {
        NSLock *lock = [NSLock new];
        then = CFAbsoluteTimeGetCurrent();
        for(i=0;i<ITERATIONS;++i)
        {
            [lock lock];
            [lock unlock];
        }
        now = CFAbsoluteTimeGetCurrent();
        printf("NSLock: %f sec\n", now-then);
        
        
        then = CFAbsoluteTimeGetCurrent();
        for(i=0;i<ITERATIONS;++i)
        {
            pthread_mutex_lock(&mutex);
            pthread_mutex_unlock(&mutex);
        }
        now = CFAbsoluteTimeGetCurrent();
        printf("pthread_mutex: %f sec\n", now-then);
        
        then = CFAbsoluteTimeGetCurrent();
        for(i=0;i<ITERATIONS;++i)
        {
            OSSpinLockLock(&spinlock);
            OSSpinLockUnlock(&spinlock);
        }
        now = CFAbsoluteTimeGetCurrent();
        printf("OSSpinlock: %f sec\n", now-then);
        
        id obj = [NSObject new];
        
        then = CFAbsoluteTimeGetCurrent();
        for(i=0;i<ITERATIONS;++i)
        {
            @synchronized(obj)
            {
            }
        }
        now = CFAbsoluteTimeGetCurrent();
        printf("@synchronized: %f sec\n", now-then);
        
        
        
    }
    
    
}

@end
